#include "ImageView.h"
#include "ImageMonitor.h"
#include <QPen>
#include <QColor>
#include <QDebug>
#include <QPainter>
#include <QMouseEvent>

const int MAX_IMAGE_SIZE_X = 10000;
const int MAX_IMAGE_SIZE_Y = 10000;
const int DEFAULT_IMAGE_SIZE_X = 1920;
const int DEFAULT_IMAGE_SIZE_Y = 1200;

//QList<QVideoFrame::PixelFormat> ImageView::supportedPixelFormats(
//        QAbstractVideoBuffer::HandleType handleType) const
//{
//    Q_UNUSED(handleType);
//    QList<QVideoFrame::PixelFormat> list;
//    list << QVideoFrame::Format_RGB32;
//    list << QVideoFrame::Format_ARGB32;
//    list << QVideoFrame::Format_RGB24;
//    return list;
//}

void ImageView::setVideoFrame(const QVideoFrame &frame)
{

    switch (frame.pixelFormat())
    {
    case QVideoFrame::Format_RGB24:
    {
        QImage image24(frame.bits(), frame.width(), frame.height(), frame.bytesPerLine(), QImage::Format_RGB888);
        setRGB24Image(image24);
    }
        break;
    case QVideoFrame::Format_RGB32:
    case QVideoFrame::Format_ARGB32:
    case QVideoFrame::Format_ARGB32_Premultiplied:
    {
        QImage image32(frame.bits(), frame.width(), frame.height(), frame.bytesPerLine(), QImage::Format_RGB32);
        setRGB32Image(image32);
    }
        break;
    default:
        break;
    }
}

//bool ImageView::present(const QVideoFrame &frame)
// {
//    // 处理捕获的帧
//    if(frame.isMapped())
//    {
//        setVideoFrame(frame);
//    }
//    else
//    {
//        QVideoFrame f = frame;
//        f.map(QAbstractVideoBuffer::ReadOnly);
//        setVideoFrame(f);
//    }
//    return true;
// }

ImageView::ImageView(ImageFormat format, QWidget *parent) :
        QWidget(parent),
//        QAbstractVideoSurface(parent),
        m_size(DEFAULT_IMAGE_SIZE_X, DEFAULT_IMAGE_SIZE_Y),
        m_zoom_factor(1.0),
        m_mouse_pos_pick(false),
        //m_image_monitor(nullptr),
        m_show_cross(true)
{
//    setMaximumSize( QSize( MAX_IMAGE_SIZE_X, MAX_IMAGE_SIZE_Y ) );
    if(format == RGB24)
    {
        m_image = QImage( m_size, QImage::Format_RGB888 );
    }
    else
    {
        m_image = QImage( m_size, QImage::Format_RGB32 );
    }

    m_image.fill( Qt::darkGray );
    setFixedSize( m_size * m_zoom_factor );
    update();
}

void ImageView::setMousePositionPickMode(bool on)
{
    m_mouse_pos_pick = on;
}

//void CameraView::mousePressEvent(QMouseEvent *event)
//{
//    //qDebug() << "ImageDisplay::mousePressEvent";
//    if(m_mouse_pos_pick && event->button() == Qt::LeftButton)
//    {
//        QPoint point = event->pos() / m_zoom_factor;
//        emit mousePosition(point);
//    }
//    QWidget::mousePressEvent(event);
//}

void ImageView::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(m_mouse_pos_pick && event->button() == Qt::RightButton)
    {
        QPoint point = event->pos() / m_zoom_factor;
        emit mousePosition(point);
    }
    QWidget::mousePressEvent(event);
}

ImageView::~ImageView()
{

}
QImage ImageView::getImage()
{
    QImage image;
    // 防止在获取图像时有其他的线程更新图像，这里要加锁
    m_image_mutex.lock();
    image = m_image.copy();
    m_image_mutex.unlock();
    return image;
}


void ImageView::fillImage(QRgb color)
{
    m_image_mutex.lock();
    m_image.fill(color);
    m_image_mutex.unlock();
    update();
}

void ImageView::fillImage(const QColor color)
{
    m_image_mutex.lock();
    m_image.fill(color);
    m_image_mutex.unlock();
    update();
}

void ImageView::fillImage(Qt::GlobalColor color)
{
    m_image_mutex.lock();
    m_image.fill(color);
    m_image_mutex.unlock();
    update();
}

bool ImageView::loadImage(const QString &fileName)
{
    QImage image;
    image.load(fileName);

    if(image.isNull())
    {
        return false;
    }

    if(image.format() != QImage::Format_RGB32 &&
       image.format() != QImage::Format_ARGB32 &&
       image.format() != QImage::Format_ARGB32_Premultiplied)
    {
        image = image.convertToFormat(QImage::Format_RGB32);
    }

    setRGB32Image(image);
    return true;
}

bool ImageView::saveImage( const QString &fileName )
{
    m_image_mutex.lock();
    QImage image = m_image.copy();
    m_image_mutex.unlock();
    return image.save(fileName);
}
void ImageView::RGB24_to_RGB32(QImage &to, const QImage &from)
{
    if(to.size() != from.size())
    {
        to = QImage(from.size(), QImage::Format_RGB32);
    }
    int imageHeight = from.height();
    int imageWidth = from.width();
    for (int row = 0; row < imageHeight; row++)
    {
        uint8_t *lineTo = (uint8_t *)to.scanLine(row);
        // 找到 CCD 数据一行的开头位置，一个像素占3字节
        uint8_t * lineFrom = (uint8_t *) from.scanLine(row);
        for (int col = 0; col < imageWidth; col ++)
        {
            *(lineTo++) = *(lineFrom++);
            *(lineTo++) = *(lineFrom++);
            *(lineTo++) = *(lineFrom++);
            *(lineTo++) = 0;
        }
    }
}

void ImageView::RGB32_to_RGB32(QImage &to, const QImage &from)
{
    if(to.size() != from.size())
    {
        to = from;
        to.detach();
        return;
    }
    uint8_t * lineFrom = (uint8_t *)from.scanLine(0);
    uint8_t * lineTo = (uint8_t *)to.scanLine(0);
    memcpy(lineTo, lineFrom, from.byteCount());
}

void ImageView::RGB24_to_RGB24(QImage &to, const QImage &from)
{
    if(to.size() != from.size())
    {
        to = from;
        to.detach();
        return;
    }
    uint8_t * lineFrom = (uint8_t *)from.scanLine(0);
    uint8_t * lineTo = (uint8_t *)to.scanLine(0);
    memcpy(lineTo, lineFrom, from.byteCount());
}

void ImageView::RGB32_to_RGB24(QImage &to, const QImage &from)
{
    if(to.size() != from.size())
    {
        to = QImage(from.size(), QImage::Format_RGB888);
    }
    int imageHeight = from.height();
    int imageWidth = from.width();
    for (int row = 0; row < imageHeight; row++)
    {
        uint8_t *lineTo = (uint8_t *)to.scanLine(row);
        uint8_t * lineFrom = (uint8_t *) from.scanLine(row);
        for (int col = 0; col < imageWidth; col ++)
        {
            *(lineTo++) = *(lineFrom++);
            *(lineTo++) = *(lineFrom++);
            *(lineTo++) = *(lineFrom++);
            lineFrom++;
        }
    }
}

void ImageView::setRGB24Image(const QImage &image)
{
    if(image.format() != QImage::Format_RGB888)
    {
        return;
    }
    if(m_image.format() == QImage::Format_RGB888)
    {
        m_image_mutex.lock();
        RGB24_to_RGB24(m_image, image);
        m_image_mutex.unlock();
    }
    else
    {
        m_image_mutex.lock();
        RGB24_to_RGB32(m_image, image);
        m_image_mutex.unlock();
    }

    if(m_size != m_image.size())
    {
        m_size = m_image.size();
        setFixedSize(m_size * m_zoom_factor);
    }

    imageChangedHook();
    update();
}

void ImageView::setRGB32Image(const QImage &image)
{
    if(image.format() != QImage::Format_RGB32 &&
       image.format() != QImage::Format_ARGB32 &&
       image.format() != QImage::Format_ARGB32_Premultiplied)
    {
        qDebug() << "image format invalid, do nothing in setRGB32Image()";
        return;
    }
    if(m_image.format() == QImage::Format_RGB888)
    {
        m_image_mutex.lock();
        RGB32_to_RGB24(m_image, image);
        m_image_mutex.unlock();
    }
    else
    {
        m_image_mutex.lock();
        RGB32_to_RGB32(m_image, image);
        m_image_mutex.unlock();
    }

    if(m_size != m_image.size())
    {
        m_size = m_image.size();
        setFixedSize(m_size * m_zoom_factor);
    }

    imageChangedHook();
    update();

}

inline void ImageView::setSize(QSize size)
{
    if(m_size == size)
    {
        return;
    }

    m_size.setWidth(qBound(1, size.width(), MAX_IMAGE_SIZE_X));
    m_size.setHeight(qBound(1, size.height(), MAX_IMAGE_SIZE_Y));
	
    if(m_image.size() == m_size)
    {
        return;
    }
	m_image_mutex.lock();
    QImage::Format format = m_image.format();
    m_image = QImage(m_size, format);
    //m_image.fill(Qt::darkGray);
    setFixedSize(m_size * m_zoom_factor);
	m_image_mutex.unlock();
}

void ImageView::setZoomFactor(double factor)
{
    factor = qBound(0.01, factor, 10.0);
    m_zoom_factor = factor;
    setFixedSize(m_size * m_zoom_factor);
    update();
}

void ImageView::setZoomFactorPCT(int factor)
{
    factor = qBound(1, factor, 1000);
    m_zoom_factor = factor / 100.0;
    setFixedSize(m_size * m_zoom_factor);
    update();
    emit zoomFactorPCTChanged(factor);
}

void ImageView::setImageMonitor(ImageMonitor *monitor)
{
    //m_image_monitor = monitor;
    if(monitor)
    {
        m_monitor_set.insert(monitor);
    }
}

void ImageView::removeAllImageMonitors()
{
    m_monitor_set.clear();
}

void ImageView::removeImageMonitor(ImageMonitor * monitor)
{
    m_monitor_set.remove(monitor);
}

void ImageView::imageChangedHook()
{
//    if( m_image_monitor )
//    {
//        m_image_monitor->imageChanged(m_image);
//    }

    QSetIterator<ImageMonitor *> iter(m_monitor_set);
    while (iter.hasNext())
    {
        ImageMonitor * p = iter.next();
        p->imageChanged(m_image);
    }
}

void ImageView::paintEventHook(QPainter &painter)
{
//    if(m_image_monitor)
//    {
//        m_image_monitor->paintHook(painter, m_zoom_factor);
//    }
    QSetIterator<ImageMonitor *> iter(m_monitor_set);
    while (iter.hasNext())
    {
        ImageMonitor * p = iter.next();
        p->paintHook(painter, m_zoom_factor);
    }
}

void ImageView::showCross(bool show)
{
    m_show_cross = show;
    update();
}

inline void ImageView::drawImage(QPainter &painter)
{
    painter.save();
    painter.scale(m_zoom_factor, m_zoom_factor);
    m_image_mutex.lock();
    painter.drawImage ( 0, 0, m_image );
    m_image_mutex.unlock();
    painter.restore();
}

inline void ImageView::drawCross(QPainter &painter)
{
    int mid_x = size().width() / 2;
    int mid_y = size().height() / 2;
    QPen pen(Qt::red);
    pen.setWidth(2);
    pen.setStyle(Qt::SolidLine);
    painter.setPen(pen);
    painter.drawLine(mid_x - 50, mid_y, mid_x + 50, mid_y);
    painter.drawLine(mid_x, mid_y - 50, mid_x, mid_y + 50);
//    pen.setColor(Qt::black);
//    painter.setPen(pen);
//    painter.drawRect ( rect() );
}

void ImageView::paintEvent( QPaintEvent * event )
{
    (void) event;
    QPainter painter(this);
    painter.setRenderHint ( QPainter::Antialiasing, true );
    drawImage(painter);
    paintEventHook(painter);
    if (m_show_cross)
    {
        drawCross(painter);
    }
}


